﻿Ext.data.WebStorageProxy = Ext.extend(Ext.data.ClientProxy, {

    id: undefined,


    constructor: function (config) {
        Ext.data.WebStorageProxy.superclass.constructor.call(this, config);

        this.cache = {};

        // 获取具体的本地存储对象
        if (this.getStorageObject() == undefined) {
            throw "Local Storage is not supported in this browser, please use another type of data proxy";
        }


        this.id = this.id || (this.store ? this.store.storeId : undefined);

        if (this.id == undefined) {
            throw "No unique id was provided to the local storage proxy. See Ext.data.LocalStorageProxy documentation for details";
        }

        this.initialize();
    },

    // 将数据保存到存储对象中
    create: function (operation, callback, scope) {
        var records = operation.records,
            length = records.length,
            ids = this.getIds(),
            id, record, i;

        operation.setStarted();

        for (i = 0; i < length; i++) {
            record = records[i];

            if (record.phantom) {
                record.phantom = false;
                id = this.getNextId();
            } else {
                id = record.getId();
            }

            this.setRecord(record, id);
            ids.push(id);
        }

        this.setIds(ids);

        operation.setCompleted();
        operation.setSuccessful();

        if (typeof callback == 'function') {
            callback.call(scope || this, operation);
        }
    },

    // 从存储对象中读取指定数据
    read: function (operation, callback, scope) {


        var records = [],
            ids = this.getIds(),
            length = ids.length,
            i, recordData, record;


        if (operation.id) {
            record = this.getRecord(operation.id);

            if (record) {
                records.push(record);
                operation.setSuccessful();
            }
        } else {
            for (i = 0; i < length; i++) {
                records.push(this.getRecord(ids[i]));
            }
            operation.setSuccessful();
        }

        operation.setCompleted();

        operation.resultSet = new Ext.data.ResultSet({
            records: records,
            total: records.length,
            loaded: true
        });

        if (typeof callback == 'function') {
            callback.call(scope || this, operation);
        }
    },

    // 更新存储对象中的指定内容
    update: function (operation, callback, scope) {
        var records = operation.records,
            length = records.length,
            ids = this.getIds(),
            record, id, i;

        operation.setStarted();

        for (i = 0; i < length; i++) {
            record = records[i];
            this.setRecord(record);



            id = record.getId();
            if (id !== undefined && ids.indexOf(id) == -1) {
                ids.push(id);
            }
        }
        this.setIds(ids);

        operation.setCompleted();
        operation.setSuccessful();

        if (typeof callback == 'function') {
            callback.call(scope || this, operation);
        }
    },

    // 移除存储对象中的指定内容
    destroy: function (operation, callback, scope) {
        var records = operation.records,
            length = records.length,
            ids = this.getIds(),


            newIds = [].concat(ids),
            i;

        for (i = 0; i < length; i++) {
            newIds.remove(records[i].getId());
            this.removeRecord(records[i], false);
        }

        this.setIds(newIds);

        if (typeof callback == 'function') {
            callback.call(scope || this, operation);
        }
    },


    getRecord: function (id) {
        if (this.cache[id] == undefined) {
            var rawData = Ext.decode(this.getStorageObject().getItem(this.getRecordKey(id))),
                data = {},
                Model = this.model,
                fields = Model.prototype.fields.items,
                length = fields.length,
                i, field, name, record;

            for (i = 0; i < length; i++) {
                field = fields[i];
                name = field.name;

                if (typeof field.decode == 'function') {
                    data[name] = field.decode(rawData[name]);
                } else {
                    data[name] = rawData[name];
                }
            }

            record = new Model(data, id);
            record.phantom = false;

            this.cache[id] = record;
        }

        return this.cache[id];
    },


    setRecord: function (record, id) {
        if (id) {
            record.setId(id);
        } else {
            id = record.getId();
        }

        var rawData = record.data,
            data = {},
            model = this.model,
            fields = model.prototype.fields.items,
            length = fields.length,
            i, field, name;

        for (i = 0; i < length; i++) {
            field = fields[i];
            name = field.name;

            if (typeof field.encode == 'function') {
                data[name] = field.encode(rawData[name], record);
            } else {
                data[name] = rawData[name];
            }
        }

        var obj = this.getStorageObject(),
            key = this.getRecordKey(id);


        this.cache[id] = record;


        obj.removeItem(key);
        obj.setItem(key, Ext.encode(data));
    },


    removeRecord: function (id, updateIds) {
        if (id instanceof Ext.data.Model) {
            id = id.getId();
        }

        if (updateIds !== false) {
            var ids = this.getIds();
            ids.remove(id);
            this.setIds(ids);
        }

        this.getStorageObject().removeItem(this.getRecordKey(id));
    },


    getRecordKey: function (id) {
        if (id instanceof Ext.data.Model) {
            id = id.getId();
        }

        return Ext.util.Format.format("{0}-{1}", this.id, id);
    },


    getRecordCounterKey: function () {
        return Ext.util.Format.format("{0}-counter", this.id);
    },


    getIds: function () {
        var ids = (this.getStorageObject().getItem(this.id) || "").split(","),
            length = ids.length,
            i;

        if (length == 1 && ids[0] == "") {
            ids = [];
        } else {
            for (i = 0; i < length; i++) {
                ids[i] = parseInt(ids[i], 10);
            }
        }

        return ids;
    },


    setIds: function (ids) {
        var obj = this.getStorageObject(),
            str = ids.join(",");

        obj.removeItem(this.id);

        if (!Ext.isEmpty(str)) {
            obj.setItem(this.id, str);
        }
    },


    getNextId: function () {
        var obj = this.getStorageObject(),
            key = this.getRecordCounterKey(),
            last = obj[key],
            ids, id;

        if (last == undefined) {
            ids = this.getIds();
            last = ids[ids.length - 1] || 0;
        }

        id = parseInt(last, 10) + 1;
        obj.setItem(key, id);

        return id;
    },


    initialize: function () {
        var storageObject = this.getStorageObject();
        storageObject.setItem(this.id, storageObject.getItem(this.id) || "");
    },


    clear: function () {
        var obj = this.getStorageObject(),
            ids = this.getIds(),
            len = ids.length,
            i;


        for (i = 0; i < len; i++) {
            this.removeRecord(ids[i]);
        }


        obj.removeItem(this.getRecordCounterKey());
        obj.removeItem(this.id);
    },


    getStorageObject: function () {
        throw new Error("The getStorageObject function has not been defined in your Ext.data.WebStorageProxy subclass");
    }
});